﻿
local low, mediun, update = 300, 600, 10
local GameTooltip = GameTooltip
local GameTimeFrame = GameTimeFrame
local MainMenuBarPerformanceBarFrameButton = MainMenuBarPerformanceBarFrameButton

local select = select
local format = string.format
local date = date
local time = time
local UpdateAddOnMemoryUsage = UpdateAddOnMemoryUsage
local GetNumAddOns = GetNumAddOns
local GetAddOnMemoryUsage = GetAddOnMemoryUsage
local GetAddOnInfo = GetAddOnInfo
local GetNetStats = GetNetStats
local GetFramerate = GetFramerate

local tdPerformanceDB = {
	max = 30,	-- 最大条数
	typ = 2,	-- 1 - 3	1:插件时钟替代原时钟	2:延迟时	3:时钟
}

local frame = CreateFrame('Button', nil, Minimap)
local topAddOns = {}

local L = {
	text = "性能  点击回收内存.",
	pingt = "延迟",
	fpst = "帧数",
	addons = "插件内存",
	other = "其它插件 |cffffffff(%d)|r",
	addon = "|cffffffff%s. |r%s",
	ping = "%d ms",
	fps = "%.0f fps",
	mb = "%.2f MB",
	kb = "%.1f KB",
}
--[[
local WindInfoDateWeek = {[0] = "日","一","二","三","四","五","六"};

local function GetDate()
	local year = date("%y", time()) + 2000;
	local mon = date("%m", time()) + 0;
	local day = date("%d", time()) + 0;
	return "|cFFFFFF00"..year.."|cFFFFFFFF".."年".."|cFFFFFF00"..mon.."|cFFFFFFFF".."月".."|cFFFFFF00"..day.."|cFFFFFFFF".."日".."|cFFFFFFFF星期".."|cFFFFFF00"..WindInfoDateWeek[tonumber(date("%w", time()))];
end
]]

local function MenToString(mem)
	if mem > 1000 then
		return format(L.mb, mem / 1000);
	else
		return format(L.kb, mem);
	end
end

local function HookFrame(frame, script, func)
	if not frame or not script then return end
	if frame:GetScript(script) then
		frame:HookScript(script, func)
	else
		frame:SetScript(script, func)
	end
end

local function GetColor(value)
	value = 1 - value
	local r, g
	if value > 0.5 then
		r = (1 - value) * 2;
		g = 1;
	else
		r = 1;
		g = value * 2;
	end
	return r, g, 0;
end

local function OnEnter(self)
	self = self or this
	local i, j, k
	local mem, allmem, showmem, loaded = 0, 0, 0, 0

	GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT")
	GameTooltip:SetText(L.text);
	GameTooltip:AddLine(" ");
	--GameTooltip:AddLine(GetDate());
	GameTooltip:AddDoubleLine(L.pingt, format(L.ping, select(3, GetNetStats())));
	GameTooltip:AddDoubleLine(L.fpst, format(L.fps, GetFramerate()));

	for i = 1, tdPerformanceDB.max do
		if not topAddOns[i] then
			topAddOns[i] = { mem = 0, name = "" };
		end
		topAddOns[i].mem = 0;
	end

	UpdateAddOnMemoryUsage()
	for i = 1, GetNumAddOns() do
		mem = GetAddOnMemoryUsage(i) or 0
		allmem = allmem + mem
		for j = 1, tdPerformanceDB.max do
			if mem > topAddOns[j].mem then
				for k = tdPerformanceDB.max, 1, -1 do
					if k == j then
						topAddOns[k].mem = mem;
						topAddOns[k].name = GetAddOnInfo(i);
						break;
					elseif k ~= 1 then
						topAddOns[k].mem = topAddOns[k-1].mem;
						topAddOns[k].name = topAddOns[k-1].name;
					end
				end
				break;
			end
		end
		if mem and mem > 0 then
			loaded = loaded + 1
		end
	end
	if allmem > 0 then
		GameTooltip:AddDoubleLine(L.addons, MenToString(allmem));
		GameTooltip:AddLine(" ");

		for i = 1, min(tdPerformanceDB.max, loaded) do
			if topAddOns[i].mem == 0 then
				break;
			end
			mem = topAddOns[i].mem;
			showmem = showmem + mem
			GameTooltip:AddDoubleLine(format(L.addon, i, topAddOns[i].name), MenToString(mem), 0, 1, 1, 1, 1, 1);
		end

		if loaded > tdPerformanceDB.max then
			GameTooltip:AddDoubleLine(format(L.other, loaded - tdPerformanceDB.max), MenToString(allmem - showmem), 0, 1, 1, 1, 1, 1);
		end
	end
	GameTooltip:Show()
end


local function OnLeave() GameTooltip:Hide() end

local function OnClick(self, ...)
	if arg1 == "LeftButton" then
		DEFAULT_CHAT_FRAME:AddMessage('|cff7fff7ftdPerformance|r:内存已回收。')
		collectgarbage('collect')
		OnEnter(self, ...)
	else
		if IsAddOnLoaded("Amp") then
			PlaySound("igMainMenuOption");
			HideUIPanel(GameMenuFrame);
			InterfaceOptionsFrame_OpenToFrame("Amp")
		elseif IsAddOnLoaded("ACP") then
			PlaySound("igMainMenuOption");
			HideUIPanel(GameMenuFrame);
			ShowUIPanel(ACP_AddonList)
		end
	end
end

local function OnUpdate(self, ...)
	if (self.nextUpdate > 0) then
		self.nextUpdate = self.nextUpdate - arg1
	else
		self.nextUpdate = update
		local latency = select(3, GetNetStats())
		if latency > mediun then
			self.ClockText:SetVertexColor(1, 0, 0)
		else
			self.ClockText:SetVertexColor(GetColor(latency / mediun))
		end
		if (self.hover) then
			OnEnter(self)
		end
	end
	local hour, minute = GetGameTime();
	self.ClockText:SetFormattedText("%d:%s", hour, minute < 10 and ("0"..minute) or minute)
end

local function LoadLate()
	MainMenuBarPerformanceBarFrame_OnEnter = function() end
	MainMenuBarPerformanceBarFrameButton:SetScript("OnClick", OnClick)
	MainMenuBarPerformanceBarFrameButton:SetScript("OnEnter", OnEnter)
	MainMenuBarPerformanceBarFrameButton:RegisterForClicks("LeftButtonUp", "RightButtonUp")
end

local function LoadTime()
	GameTimeFrame.hover = nil
	GameTimeFrame.nextUpdate = 0
	GameTimeFrame.ClockText = GameTimeFrame:CreateFontString(nil, "ARTWORK", "NumberFontNormal")
	GameTimeFrame.ClockText:SetPoint("CENTER")

	GameTimeFrame:SetScript("OnEnter", OnEnter)
	GameTimeFrame:SetScript("OnMouseUp", OnClick)
	HookFrame(GameTimeFrame, "OnUpdate", OnUpdate)
	GameTimeFrame.updateTooltip = nil
	GameTimeFrame_UpdateTooltip = function() end
end

local function LoadSelf()
	frame.hover = nil
	frame.nextUpdate = 0
	frame:SetBackdrop{
	  bgFile = 'Interface/ChatFrame/ChatFrameBackground',
	  edgeFile = 'Interface/Tooltips/UI-Tooltip-Border',
	  edgeSize = 16,
	  tile = true, tileSize = 16,
	  insets = {left = 4, right = 4, top = 4, bottom = 4}
	}
	frame:SetBackdropColor(0,0,0,0.8)
	frame:EnableMouse(true)
	frame:SetFrameStrata("HIGH")
	frame:SetToplevel(true)
	frame:SetMovable(true)
	frame:SetWidth(50) frame:SetHeight(26)
	frame:SetPoint("CENTER", GameTimeFrame, "CENTER", -3, 5)
	frame.ClockText = frame:CreateFontString(nil, "ARTWORK", "NumberFontNormal")
	frame.ClockText:SetPoint("CENTER")
	frame:RegisterForClicks("LeftButtonUp", "RightButtonUp")

	frame:SetScript("OnUpdate", OnUpdate)
	frame:SetScript("OnEnter", OnEnter)
	frame:SetScript("OnLeave", OnLeave)
	frame:SetScript("OnClick", OnClick)

	GameTimeFrame:Hide()
	GameTimeFrame:SetScript("OnUpdate", nil)
	GameTimeFrame:SetScript("OnEnter", nil)
	GameTimeFrame:SetScript("OnLeave", nil)
	GameTimeFrame.updateTooltip = nil
	GameTimeFrame.Show = function() end
end

frame:SetScript("OnEvent", function(self)
	for i = 1, tdPerformanceDB.max do
		topAddOns[i] = { mem = 0, name = "" };
	end
	if tdPerformanceDB.typ == 1 then
		LoadSelf()
	elseif tdPerformanceDB.typ == 2 then
		LoadLate()
	elseif tdPerformanceDB.typ == 3 then
		LoadTime()
	end
	self:UnregisterEvent("VARIABLES_LOADED")
end)
frame:RegisterEvent("VARIABLES_LOADED")